﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using KWR.DAL;

namespace AffineTransformation
{
    public partial class Main : Form
    {
        string kwrName = string.Empty;
        string chaosName = string.Empty;

        Bitmap orginal;

        public Main()
        {
            InitializeComponent();
        }

        public bool ThumbnailCallback()
        {
            return false;
        }

        private void Main_Load(object sender, EventArgs e)
        {
            DataTable dt = null;

            dt = DataAccess.GetChaos();

            foreach (DataRow item in dt.Rows)
            {
                cbChaosNames.Items.Add(item["name"]);
            }
        }

        private void cbKWR_SelectedIndexChanged(object sender, EventArgs e)
        {
            ToolStripComboBox cb = (ToolStripComboBox)sender;
            kwrName = cb.SelectedItem.ToString();
        }

        private double x0, y0, xn, yn;
        Random random = new Random();

        
        Bitmap chaosImage = null;

        private void cbChaosNames_SelectedIndexChanged(object sender, EventArgs e)
        {
            ToolStripComboBox cb = (ToolStripComboBox)sender;
            chaosName = cb.SelectedItem.ToString();

            x0 = random.NextDouble();
            y0 = random.NextDouble();

            chaosImage = new Bitmap(picImage.Width, picImage.Height);

            int newX = Convert.ToInt32(x0 * Convert.ToDouble(picImage.Width));
            int newY = Convert.ToInt32(y0 * Convert.ToDouble(picImage.Height));

            try
            {
                chaosImage.SetPixel(newX - 1, newY - 1, Color.Red);
            }
            catch { };

            try
            {
                chaosImage.SetPixel(newX, newY - 1, Color.Red);
            }
            catch { };

            try
            {
                chaosImage.SetPixel(newX + 1, newY - 1, Color.Red);
            }
            catch { };

            try
            {
                chaosImage.SetPixel(newX - 1, newY, Color.Red);
            }
            catch { };

            try
            {
                chaosImage.SetPixel(newX, newY, Color.Red);
            }
            catch { };

            try
            {
                chaosImage.SetPixel(newX + 1, newY, Color.Red);
            }
            catch { };

            try
            {
                chaosImage.SetPixel(newX - 1, newY + 1, Color.Red);
            }
            catch { };

            try
            {
                chaosImage.SetPixel(newX, newY + 1, Color.Red);
            }
            catch { };

            try
            {
                chaosImage.SetPixel(newX + 1, newY + 1, Color.Red);
            }
            catch { };
        }

        private void getProb(double[] p, out int id)
        {
            id = 0;

            double newProb = random.NextDouble();

            for (int i = p.Length - 1; i > 0; i--)
            {
                if (newProb > p[i - 1] && newProb <= p[i])
                {
                    id = i - 1;
                    break;
                }
            }
        }

        private void getProb2(double[] p, out int id)
        {
            id = 0;

            double num = random.NextDouble();

            for (int j = 0; j <= p.Length - 1; j++)
            {
                num = num - p[j];
                if (num <= 0)
                {
                    id = j;
                    break;
                }
            }
        }

        private void chaosGame(int howMany)
        {
            if (string.IsNullOrEmpty(chaosName))
            {
                return;
            }

            DataTable dt = DataAccess.GetAllChaosTransformations(chaosName);

            double[,] coof = new double[dt.Rows.Count, 6];

            for (int i = 0; i < dt.Rows.Count; i++)
            {
                coof[i, 0] = Convert.ToDouble(dt.Rows[i]["a"]);
                coof[i, 1] = Convert.ToDouble(dt.Rows[i]["b"]);
                coof[i, 2] = Convert.ToDouble(dt.Rows[i]["c"]);
                coof[i, 3] = Convert.ToDouble(dt.Rows[i]["d"]);
                coof[i, 4] = Convert.ToDouble(dt.Rows[i]["e"]);
                coof[i, 5] = Convert.ToDouble(dt.Rows[i]["f"]);
            }

            dt = DataAccess.GetChaosProbability(chaosName);

            double[] p = new double[dt.Rows.Count + 1];
            double[] p2 = new double[dt.Rows.Count];

            double pSum = 0;

            p[0] = 0.00;

            for (int j = 1; j <= dt.Rows.Count; j++)
            {
                pSum += Convert.ToDouble(dt.Rows[j - 1][0]);

                p[j] = pSum;
                p2[j - 1] = Convert.ToDouble(dt.Rows[j - 1][0]);
            }

            int blackCount = 0, redCount = 0, greenCount = 0, blueCount = 0;

            for (int i = 1; i < howMany; i++)
            {
                int id;

                getProb2(p2, out id);

                double x = (x0 * coof[id, 0] + y0 * coof[id, 1] + coof[id, 4]);
                double y = (x0 * coof[id, 2] + y0 * coof[id, 3] + coof[id, 5]);

                x0 = x;
                y0 = y;

                if (chaosName.ToLower() == "game i" || chaosName.ToLower() == "game ii" || chaosName.ToLower() == "game ix")
                {
                    int newX = Convert.ToInt32(x * Convert.ToDouble(picImage.Width));
                    int newY = Convert.ToInt32(y * Convert.ToDouble(picImage.Height));

                    if (newX >= 0 && newY >= 0 && newX < picImage.Width && newY < picImage.Height)
                    {
                        chaosImage.SetPixel(newX, newY, Color.Black);
                    }
                }
                else if (chaosName.ToLower() == "game iii" || chaosName.ToLower() == "game iv")
                {
                    const double W_XMIN = -4;
                    const double W_XMAX = 4;
                    const double W_YMIN = -0.1f;
                    const double W_YMAX = 10.1f;
                    const double W_WID = W_XMAX - W_XMIN;
                    const double W_HGT = W_YMAX - W_YMIN;
                    int ix = (int)Math.Round((x - W_XMIN) / W_WID * picImage.Width);
                    int iy = (int)Math.Round((picImage.Height - 1) - (y - W_YMIN) / W_HGT * picImage.Height);
                    if ((ix >= 0) && (iy >= 0)
                        && (ix < picImage.Width)
                        && (iy < picImage.Height))
                    {
                        //chaosImage.SetPixel(ix, iy, Color.Black);
                        if (id == 0)
                        {
                            chaosImage.SetPixel(ix, iy, Color.Brown);
                            blackCount ++;
                        }
                        else if (id == 1)
                        {
                            chaosImage.SetPixel(ix, iy, Color.Red);
                            redCount++;
                        }
                        else if (id == 2)
                        {
                            chaosImage.SetPixel(ix, iy, Color.Green);
                            greenCount++;
                        }
                        else if (id == 3)
                        {
                            chaosImage.SetPixel(ix, iy, Color.Blue);
                            blueCount++;
                        }
                    }
                }
                else if (chaosName.ToLower() == "game v")
                {
                    const double W_XMIN = -2;
                    const double W_XMAX = 2;
                    const double W_YMIN = -0.1f;
                    const double W_YMAX = 9.1f;
                    const double W_WID = W_XMAX - W_XMIN;
                    const double W_HGT = W_YMAX - W_YMIN;
                    int ix = (int)Math.Round((x - W_XMIN) / W_WID * picImage.Width);
                    int iy = (int)Math.Round((picImage.Height - 1) - (y - W_YMIN) / W_HGT * picImage.Height);
                    if ((ix >= 0) && (iy >= 0)
                        && (ix < picImage.Width)
                        && (iy < picImage.Height))
                    {
                        chaosImage.SetPixel(ix, iy, Color.Black);
                    }
                }
                else if (chaosName.ToLower() == "game vi")
                {
                    const double W_XMIN = 0;
                    const double W_XMAX = 1;
                    const double W_YMIN = -0.1f;
                    const double W_YMAX = 0.9f;
                    const double W_WID = W_XMAX - W_XMIN;
                    const double W_HGT = W_YMAX - W_YMIN;
                    int ix = (int)Math.Round((x - W_XMIN) / W_WID * picImage.Width);
                    int iy = (int)Math.Round((picImage.Height - 1) - (y - W_YMIN) / W_HGT * picImage.Height);
                    if ((ix >= 0) && (iy >= 0)
                        && (ix < picImage.Width)
                        && (iy < picImage.Height))
                    {
                        // Czarne drzewo
                        chaosImage.SetPixel(ix, iy, Color.Black);

                        // Wiosenne drzewo
                        if (Convert.ToDouble(i) > 0.90 * Convert.ToDouble(howMany))
                            chaosImage.SetPixel(ix, iy, Color.Brown);
                        else
                            chaosImage.SetPixel(ix, iy, Color.Green);
                    }
                }
                else if (chaosName.ToLower() == "game vii")
                {
                    const double W_XMIN = 0;
                    const double W_XMAX = 1;
                    const double W_YMIN = -0.1f;
                    const double W_YMAX = 1.1f;
                    const double W_WID = W_XMAX - W_XMIN;
                    const double W_HGT = W_YMAX - W_YMIN;
                    int ix = (int)Math.Round((x - W_XMIN) / W_WID * picImage.Width);
                    int iy = (int)Math.Round((picImage.Height - 1) - (y - W_YMIN) / W_HGT * picImage.Height);
                    if ((ix >= 0) && (iy >= 0)
                        && (ix < picImage.Width)
                        && (iy < picImage.Height))
                    {
                        //chaosImage.SetPixel(ix, iy, Color.Black);
                        if (id == 0)
                        {
                            chaosImage.SetPixel(ix, iy, Color.Indigo);
                        }
                        else if (id == 1)
                        {
                            chaosImage.SetPixel(ix, iy, Color.Blue);
                        }
                        else if (id == 2)
                        {
                            chaosImage.SetPixel(ix, iy, Color.BlueViolet);
                        }
                    }
                }
                else if (chaosName.ToLower() == "game viii")
                {
                    const double W_XMIN = 0;
                    const double W_XMAX = 1;
                    const double W_YMIN = -0.1f;
                    const double W_YMAX = 0.9f;
                    const double W_WID = W_XMAX - W_XMIN;
                    const double W_HGT = W_YMAX - W_YMIN;
                    int ix = (int)Math.Round((x - W_XMIN) / W_WID * picImage.Width);
                    int iy = (int)Math.Round((picImage.Height - 1) - (y - W_YMIN) / W_HGT * picImage.Height);
                    if ((ix >= 0) && (iy >= 0)
                        && (ix < picImage.Width)
                        && (iy < picImage.Height))
                    {
                        chaosImage.SetPixel(ix, iy, Color.Black);
                    }
                }
            }

            picImage.Image = chaosImage;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            chaosGame(1);

            this.Cursor = Cursors.Arrow;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            chaosGame(100);

            this.Cursor = Cursors.Arrow;
        }

        private void button4_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            chaosGame(1000);

            this.Cursor = Cursors.Arrow;
        }

        private void button5_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            chaosGame(10000);

            this.Cursor = Cursors.Arrow;
        }

        private void button6_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            chaosGame(100000);

            this.Cursor = Cursors.Arrow;
        }
    }
}
